package com.cs410.collabwriting.junit.main;

import java.util.ArrayList;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;

import com.cs410.collabwriting.main.DatabaseObjects;
import com.cs410.collabwriting.main.Prompt;
import com.cs410.collabwriting.main.Story;
import com.cs410.collabwriting.main.StoryManager;
import com.cs410.collabwriting.main.User;
import com.cs410.collabwriting.main.UserManager;
import com.cs410.collabwriting.test.DatabaseUtility;
import com.cs410.collabwriting.tools.DatabaseManager;
import com.cs410.collabwriting.tools.LogManager;
import com.cs410.collabwriting.tools.queryTools.DatabaseTable;
import com.cs410.collabwriting.tools.queryTools.QueryBuilder;
import com.cs410.collabwriting.tools.queryTools.QueryCondition;
import com.cs410.collabwriting.tools.queryTools.QueryType;
import com.cs410.collabwriting.tools.queryTools.tables.STORYLISTNAME_TABLE;

import junit.framework.Assert;

public class StoryManagerTest {

    @Rule
    public TestName m_testName = new TestName();
    private static StoryManager sm;
    private static User test_user;
    
    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        LogManager.logInfo("[JUnitTest] -- Starting JUnit Tests for StoryManager" );
        DatabaseUtility.DeleteAllTables();        
        Thread.sleep(1000);        
        DatabaseUtility.CreateAllTables();        
        Thread.sleep(1000);        
        DatabaseUtility.CreateAllTestingData();
        Thread.sleep(15000);
        
        sm = StoryManager.getInstance();
        test_user = UserManager.getInstance().addUser("test_user", "password", "email");
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        LogManager.logInfo("[JUnitTest] -- Finished JUnit Tests for StoryManager" );
    }

    @Before
    public void setUp() throws Exception {
        LogManager.logInfo("[JUnitTest] -- Starting Test : " + m_testName.getMethodName() );
    }

    @After
    public void tearDown() throws Exception {
        LogManager.logInfo("[JUnitTest] -- Finished Test : " + m_testName.getMethodName() );
    }
    
    @Test
    public void getStoriesInStoryListTest() {
        sm.createStorylist(m_testName.getMethodName(), test_user.getUserID());

        ArrayList<String[]> lists = DatabaseManager.executeQuery(
            new QueryBuilder(QueryType.SELECTION)
            .addColumns(STORYLISTNAME_TABLE.LISTID)
            .addTables(DatabaseTable.STORYLISTNAME_TABLE)
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.NAME, QueryCondition.EQ, m_testName.getMethodName())
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.USERID, QueryCondition.EQ, "test_user"));
        String listid = lists.get(0)[0];
        Assert.assertNotNull(sm.getStoriesInList(listid));
        Assert.assertEquals(0, sm.getStoriesInList(listid).size());

        Story story = sm.createStory(m_testName.getMethodName(), test_user.getUserID(), null);
        story.contributePost(test_user.getUserID(), "test post");
        sm.addStoryToStorylist(listid, Integer.toString(story.getStoryID()));
    }
    
    @Test
    public void getMostRecentStoryUpdatesTest() {
        ArrayList<String[]> stories = sm.getMostRecentStoryUpdates();
        Assert.assertNotNull(stories);
        Assert.assertTrue(stories.size() > 0);
        Assert.assertTrue(stories.size() <= 11);
    }
    
    @Test
    public void createStoryTest() {
        int size = sm.getAll().size();
        Story story = sm.createStory(m_testName.getMethodName(), test_user.getUserID(), null);
        story.contributePost(test_user.getUserID(), "test post");
        Assert.assertNotNull(story);

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
        
        int newSize = sm.getAll().size();
        Assert.assertEquals(size + 1, newSize);
                
        Prompt p = new Prompt();
        p.setTextPrompt("test prompt");
        p.setUserID(test_user.getUserID());
        p.create();

        Story story2 = sm.createStory(m_testName.getMethodName() + "2", test_user.getUserID(), p);
        story2.contributePost(test_user.getUserID(), "test post");
        Assert.assertNotNull(story2);
        
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
        
        int newSize2 = sm.getAll().size();
        Assert.assertEquals(newSize + 1, newSize2);
    }
    
    @Test
    public void getStoryByIdTest() {
        Story story1 = sm.createStory(m_testName.getMethodName(), test_user.getUserID(), null);
        story1.contributePost(test_user.getUserID(), "test post");
        Story story2 = sm.getStoryByID(story1.getStoryID());
        
        Assert.assertEquals(story1.getStoryID(), story2.getStoryID());
    }
    
    @Test
    public void getTopVotedStoriesTest() {
        Assert.assertTrue(sm.getTopVotedStories(3).size() <= 4);
        Assert.assertTrue(sm.getTopVotedStories(20).size() <= 21);        
    }
    
    @Test
    public void getTopViewedStoriesTest() {
        Assert.assertTrue(sm.getTopViewedStories(3).size() <= 4);
        Assert.assertTrue(sm.getTopViewedStories(20).size() <= 21);        
    }
    
    @Test
    public void advancedSearchTest() {
        ArrayList<DatabaseObjects> stories = sm.advancedSearch("title", "author", null, "byview");
        Assert.assertNotNull(stories);
        Assert.assertEquals(0, stories.size());
        
        String[] tags = {"tag", "tags"};
        stories = sm.advancedSearch("test", "test", tags, "byview");
        Assert.assertNotNull(stories);
        Assert.assertEquals(0, stories.size());

        stories = sm.advancedSearch("test", "test", tags, "byview");
        Assert.assertNotNull(stories);
        Assert.assertEquals(0, stories.size());
    }
    
    @Test
    public void getAllPromptTest() {
        ArrayList<Prompt> prompts = sm.getAllPrompt();
        Assert.assertNotNull(prompts);
        Assert.assertTrue(prompts.size() > 0);
    }
    
    @Test
    public void getStorylistNameFromIdTest() {
        String name =  m_testName.getMethodName();
        sm.createStorylist(name, test_user.getUserID());

        ArrayList<String[]> lists = DatabaseManager.executeQuery(
            new QueryBuilder(QueryType.SELECTION)
            .addColumns(STORYLISTNAME_TABLE.LISTID)
            .addTables(DatabaseTable.STORYLISTNAME_TABLE)
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.NAME, QueryCondition.EQ,  m_testName.getMethodName())
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.USERID, QueryCondition.EQ, test_user.getUserID()));
        
        Assert.assertEquals(name, sm.getStorylistNameFromId(lists.get(0)[0]));
    }
    
    @Test
    public void getStorylistOwnerTest() {
        sm.createStorylist( m_testName.getMethodName(), test_user.getUserID());
        
        ArrayList<String[]> lists = DatabaseManager.executeQuery(
            new QueryBuilder(QueryType.SELECTION)
            .addColumns(STORYLISTNAME_TABLE.LISTID)
            .addTables(DatabaseTable.STORYLISTNAME_TABLE)
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.NAME, QueryCondition.EQ, m_testName.getMethodName())
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.USERID, QueryCondition.EQ, test_user.getUserID()));
        
        Assert.assertEquals(test_user.getUserID(), sm.getStorylistOwner(lists.get(0)[0]));        
    }
    
    @Test
    public void getStorylistsOfUser() {
        int size = sm.getStorylistsOfUser(test_user.getUserID()).size();        
        Assert.assertTrue(sm.getStorylistsOfUser(test_user.getUserID()).size() > 0 );
        
        ArrayList<String[]> lists = DatabaseManager.executeQuery(
            new QueryBuilder(QueryType.SELECTION)
            .addColumns("COUNT(" + STORYLISTNAME_TABLE.LISTID + ")")
            .addTables(DatabaseTable.STORYLISTNAME_TABLE)
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.USERID, QueryCondition.EQ, test_user.getUserID()));
        
        Assert.assertEquals(Integer.parseInt(lists.get(0)[0]), size);
    }
    
    @Test
    public void createRenameDeleteStorylistTest() {
        Assert.assertTrue(sm.createStorylist( m_testName.getMethodName() + "1", test_user.getUserID()));

        ArrayList<String[]> lists = DatabaseManager.executeQuery(
            new QueryBuilder(QueryType.SELECTION)
            .addColumns(STORYLISTNAME_TABLE.LISTID)
            .addTables(DatabaseTable.STORYLISTNAME_TABLE)
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.NAME, QueryCondition.EQ,  m_testName.getMethodName() + "1")
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.USERID, QueryCondition.EQ, test_user.getUserID()));
        
        Assert.assertTrue(sm.renameStorylist(lists.get(0)[0],  m_testName.getMethodName() + "2"));
        Assert.assertTrue(sm.deleteStorylist(lists.get(0)[0]));
    }

    @Test
    public void getListsToAddStoryToTest() {
        Story story = sm.createStory(m_testName.getMethodName(), test_user.getUserID(), null);
        
        Assert.assertEquals(sm.getStorylistsOfUser(test_user.getUserID()).size(), 
            sm.getListsToAddStoryTo(test_user.getUserID(), Integer.toString(story.getStoryID())).size());        
    }
    
    @Test
    public void addRemoveStoryFromStorylist() {
        String name =  m_testName.getMethodName();
        sm.createStorylist(name, test_user.getUserID());

        ArrayList<String[]> lists = DatabaseManager.executeQuery(
            new QueryBuilder(QueryType.SELECTION)
            .addColumns(STORYLISTNAME_TABLE.LISTID)
            .addTables(DatabaseTable.STORYLISTNAME_TABLE)
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.NAME, QueryCondition.EQ,  m_testName.getMethodName())
            .addConditions(QueryCondition.AND, STORYLISTNAME_TABLE.USERID, QueryCondition.EQ, test_user.getUserID()));
        String listid = lists.get(0)[0];

        Story story = sm.createStory(name, test_user.getUserID(), null);
        story.contributePost(test_user.getUserID(), "test post");
        
        Assert.assertTrue(sm.addStoryToStorylist(listid, Integer.toString(story.getStoryID())));
        Assert.assertTrue(sm.removeStoryFromStorylist(Integer.toString(story.getStoryID()), listid));
    }
}
